<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>DDS参数控制器-章立靖</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            primary: '#3b82f6',
            secondary: '#64748b',
            accent: '#06b6d4',
            neutral: '#f1f5f9',
            success: '#10b981',
            warning: '#f59e0b',
            danger: '#ef4444',
          },
          fontFamily: {
            inter: ['Inter', 'system-ui', 'sans-serif'],
          },
        },
      }
    }
  </script>
  <style type="text/tailwindcss">
    @layer utilities {
      .content-auto {
        content-visibility: auto;
      }
      .bg-gradient-primary {
        background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
      }
      .transition-all-300 {
        transition: all 300ms ease-in-out;
      }
      .shadow-depth {
        box-shadow: 0 10px 25px -5px rgba(59, 130, 246, 0.1), 0 8px 10px -6px rgba(59, 130, 246, 0.1);
      }
      .text-shadow {
        text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
      }
    }
  </style>
</head>
<body class="font-inter bg-gray-50 min-h-screen flex flex-col">
  <!-- 导航栏 -->
  <header class="bg-gradient-primary text-white shadow-lg">
    <div class="container mx-auto px-4 py-3 flex justify-between items-center">
      <div class="flex items-center space-x-2">
        <i class="fa-solid fa-microchip text-2xl"></i>
        <h1 class="text-xl md:text-2xl font-bold text-shadow">DDS参数控制器上位机V1.0-章立靖</h1>
      </div>
      <div class="flex items-center space-x-4">
        <button id="theme-toggle" class="p-2 rounded-full hover:bg-white/20 transition-all-300">
          <i class="fa-solid fa-moon"></i>
        </button>
        <button id="help-btn" class="p-2 rounded-full hover:bg-white/20 transition-all-300">
          <i class="fa-solid fa-question-circle"></i>
        </button>
      </div>
    </div>
  </header>

  <!-- 主内容区 -->
  <main class="flex-grow container mx-auto px-4 py-6 flex flex-col md:flex-row gap-6">
    <!-- 左侧：协议生成 -->
    <section class="w-full md:w-1/2 bg-white rounded-xl shadow-depth p-6 transition-all-300 hover:shadow-lg">
      <h2 class="text-xl font-bold mb-4 text-gray-800 flex items-center">
        <i class="fa-solid fa-code mr-2 text-primary"></i>协议参数设置
      </h2>
      
      <div class="space-y-4">
        <!-- 命令选择 -->
        <div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
          <h3 class="font-medium text-gray-800 mb-3 flex items-center">
            <i class="fa-solid fa-terminal text-primary mr-2"></i>命令选择
          </h3>
          <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
            <!-- 通道选择 -->
            <div>
              <label for="channel-select" class="block text-sm font-medium text-gray-700 mb-1">
                通道
              </label>
              <select id="channel-select" class="w-full pl-3 pr-8 py-2 border border-gray-300 rounded-lg appearance-none focus:ring-2 focus:ring-primary/50 focus:border-primary transition-all-300 bg-white">
                <option value="1">通道 1</option>
                <option value="2">通道 2</option>
              </select>
            </div>
            
            <!-- 功能选择 -->
            <div>
              <label for="function-select" class="block text-sm font-medium text-gray-700 mb-1">
                功能
              </label>
              <select id="function-select" class="w-full pl-3 pr-8 py-2 border border-gray-300 rounded-lg appearance-none focus:ring-2 focus:ring-primary/50 focus:border-primary transition-all-300 bg-white">
                <option value="waveform">波形设置</option>
                <option value="frequency">频率设置</option>
                <option value="phase">相位设置</option>
              </select>
            </div>
          </div>
        </div>
        
        <!-- 参数设置 -->
        <div id="parameter-settings" class="bg-gray-50 p-4 rounded-lg border border-gray-200">
          <h3 class="font-medium text-gray-800 mb-3 flex items-center">
            <i class="fa-solid fa-sliders text-primary mr-2"></i><span id="parameter-title">波形设置</span>
          </h3>
          
          <!-- 波形设置 -->
          <div id="waveform-settings" class="form-group">
            <label for="waveform-value" class="block text-sm font-medium text-gray-700 mb-1">
              波形类型
            </label>
            <select id="waveform-value" class="w-full pl-3 pr-8 py-2 border border-gray-300 rounded-lg appearance-none focus:ring-2 focus:ring-primary/50 focus:border-primary transition-all-300 bg-white">
              <option value="01">正弦波 (0x01)</option>
              <option value="02">方波 (0x02)</option>
              <option value="04">三角波 (0x04)</option>
            </select>
          </div>
          
          <!-- 频率设置 -->
          <div id="frequency-settings" class="form-group hidden">
            <div class="flex items-center justify-between mb-1">
              <label for="frequency-value" class="block text-sm font-medium text-gray-700">
                频率 (kHz)
              </label>
              <span id="frequency-hex" class="text-xs text-gray-500">0x00 0x00</span>
            </div>
            <input type="number" id="frequency-value" class="w-full pl-3 pr-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary transition-all-300" placeholder="5000" value="5000" min="0" max="10000">
          </div>
          
          <!-- 相位设置 -->
          <div id="phase-settings" class="form-group hidden">
            <label for="phase-value" class="block text-sm font-medium text-gray-700 mb-1">
              相位 (范围: 0 - 4096)
            </label>
            <input type="number" id="phase-value" class="w-full pl-3 pr-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary transition-all-300" min="0" max="2048" value="0">
          </div>
        </div>
        
        <div class="form-group">
          <label class="block text-sm font-medium text-gray-700 mb-1">协议参数</label>
          <div class="grid grid-cols-2 gap-4">
            <div>
              <label class="block text-xs text-gray-500 mb-1">包头</label>
              <div class="flex items-center">
                <span class="inline-block w-2 h-2 rounded-full bg-primary mr-2"></span>
                <span id="header-value" class="font-mono text-gray-800">0x55</span>
              </div>
            </div>
            <div>
              <label class="block text-xs text-gray-500 mb-1">校验方式</label>
              <div class="flex items-center">
                <i class="fa-solid fa-calculator mr-2 text-primary"></i>
                <span id="checksum-type" class="font-mono text-gray-800">和校验 (低8位)</span>
              </div>
            </div>
          </div>
        </div>
        
        <button id="generate-btn" class="w-full bg-primary hover:bg-primary/90 text-white font-medium py-2 px-4 rounded-lg transition-all-300 flex items-center justify-center">
          <i class="fa-solid fa-cogs mr-2"></i>计算校验并生成协议
        </button>
      </div>
      
      <div id="protocol-result" class="mt-6 p-4 bg-gray-50 rounded-lg border border-gray-200 hidden">
        <h3 class="font-medium text-gray-800 mb-3">生成的协议数据包</h3>
        <div class="space-y-2">
          <div class="grid grid-cols-2 gap-2">
            <div class="text-sm text-gray-600">包头:</div>
            <div id="result-header" class="font-mono text-gray-800">0x55</div>
          </div>
          <div class="grid grid-cols-2 gap-2">
            <div class="text-sm text-gray-600">命令:</div>
            <div id="result-command" class="font-mono text-gray-800">0x10</div>
          </div>
          <div class="grid grid-cols-2 gap-2">
            <div class="text-sm text-gray-600">数据长度:</div>
            <div id="result-data-length" class="font-mono text-gray-800">0x0A</div>
          </div>
          <div class="grid grid-cols-2 gap-2">
            <div class="text-sm text-gray-600">数据:</div>
            <div id="result-data" class="font-mono text-gray-800">0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 0x99 0xAA</div>
          </div>
          <div class="grid grid-cols-2 gap-2">
            <div class="text-sm text-gray-600">校验值:</div>
            <div id="result-checksum" class="font-mono text-success font-medium">0xAB</div>
          </div>
          <div class="grid grid-cols-1 mt-2">
            <div class="text-sm text-gray-600">完整数据包:</div>
            <div id="result-full-packet" class="font-mono text-gray-800 bg-white p-2 rounded border border-gray-200 overflow-x-auto">
              0x55 0x10 0x0A 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 0x99 0xAA 0xAB
            </div>
          </div>
        </div>
      </div>
    </section>
    
    <!-- 右侧：串口通信 -->
    <section class="w-full md:w-1/2 bg-white rounded-xl shadow-depth p-6 transition-all-300 hover:shadow-lg">
      <h2 class="text-xl font-bold mb-4 text-gray-800 flex items-center">
        <i class="fa-solid fa-plug mr-2 text-primary"></i>串口通信设置
      </h2>
      
      <div id="serial-connection" class="space-y-4">
        <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
          <div>
            <label for="serial-port" class="block text-sm font-medium text-gray-700 mb-1">
              串口端口
            </label>
            <div class="relative">
              <select id="serial-port" class="w-full pl-3 pr-8 py-2 border border-gray-300 rounded-lg appearance-none focus:ring-2 focus:ring-primary/50 focus:border-primary transition-all-300 bg-white">
                <option value="">请选择串口</option>
              </select>
              <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-500">
                <i class="fa-solid fa-chevron-down text-xs"></i>
              </div>
            </div>
          </div>
          
          <div>
            <label for="baud-rate" class="block text-sm font-medium text-gray-700 mb-1">
              波特率
            </label>
            <div class="relative">
              <select id="baud-rate" class="w-full pl-3 pr-8 py-2 border border-gray-300 rounded-lg appearance-none focus:ring-2 focus:ring-primary/50 focus:border-primary transition-all-300 bg-white">
                <option value="9600">9600</option>
                <option value="115200" selected>115200</option>
                <option value="57600">57600</option>
                <option value="38400">38400</option>
              </select>
              <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-500">
                <i class="fa-solid fa-chevron-down text-xs"></i>
              </div>
            </div>
          </div>
        </div>
        
        <div class="grid grid-cols-3 gap-4">
          <div>
            <label for="data-bits" class="block text-sm font-medium text-gray-700 mb-1">
              数据位
            </label>
            <div class="relative">
              <select id="data-bits" class="w-full pl-3 pr-8 py-2 border border-gray-300 rounded-lg appearance-none focus:ring-2 focus:ring-primary/50 focus:border-primary transition-all-300 bg-white">
                <option value="8" selected>8</option>
                <option value="7">7</option>
                <option value="6">6</option>
                <option value="5">5</option>
              </select>
              <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-500">
                <i class="fa-solid fa-chevron-down text-xs"></i>
              </div>
            </div>
          </div>
          
          <div>
            <label for="parity" class="block text-sm font-medium text-gray-700 mb-1">
              校验位
            </label>
            <div class="relative">
              <select id="parity" class="w-full pl-3 pr-8 py-2 border border-gray-300 rounded-lg appearance-none focus:ring-2 focus:ring-primary/50 focus:border-primary transition-all-300 bg-white">
                <option value="none" selected>无</option>
                <option value="even">偶校验</option>
                <option value="odd">奇校验</option>
              </select>
              <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-500">
                <i class="fa-solid fa-chevron-down text-xs"></i>
              </div>
            </div>
          </div>
          
          <div>
            <label for="stop-bits" class="block text-sm font-medium text-gray-700 mb-1">
              停止位
            </label>
            <div class="relative">
              <select id="stop-bits" class="w-full pl-3 pr-8 py-2 border border-gray-300 rounded-lg appearance-none focus:ring-2 focus:ring-primary/50 focus:border-primary transition-all-300 bg-white">
                <option value="1" selected>1</option>
                <option value="2">2</option>
              </select>
              <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-500">
                <i class="fa-solid fa-chevron-down text-xs"></i>
              </div>
            </div>
          </div>
        </div>
        
        <div class="flex space-x-4">
          <button id="connect-btn" class="flex-1 bg-success hover:bg-success/90 text-white font-medium py-2 px-4 rounded-lg transition-all-300 flex items-center justify-center">
            <i class="fa-solid fa-plug mr-2"></i>连接串口
          </button>
          <button id="disconnect-btn" class="flex-1 bg-danger hover:bg-danger/90 text-white font-medium py-2 px-4 rounded-lg transition-all-300 flex items-center justify-center" disabled>
            <i class="fa-solid fa-plug-circle-xmark mr-2"></i>断开连接
          </button>
        </div>
      </div>
      
      <div id="serial-status" class="mt-6 p-3 bg-gray-50 rounded-lg border border-gray-200 hidden">
        <div class="flex items-center justify-between">
          <div class="flex items-center">
            <span id="connection-status" class="inline-block w-3 h-3 rounded-full bg-gray-400 mr-2"></span>
            <span id="connection-text" class="text-sm font-medium">未连接</span>
          </div>
          <div class="text-xs text-gray-500">
            <span id="port-info"></span>
          </div>
        </div>
      </div>
      
      <div id="serial-actions" class="mt-4 space-y-4 hidden">
        <button id="send-btn" class="w-full bg-primary hover:bg-primary/90 text-white font-medium py-2 px-4 rounded-lg transition-all-300 flex items-center justify-center" disabled>
          <i class="fa-solid fa-paper-plane mr-2"></i>发送数据包
        </button>
        
        <div class="grid grid-cols-2 gap-4">
          <button id="clear-tx-btn" class="bg-gray-200 hover:bg-gray-300 text-gray-800 font-medium py-2 px-4 rounded-lg transition-all-300 flex items-center justify-center">
            <i class="fa-solid fa-trash mr-2"></i>清空发送区
          </button>
          <button id="clear-rx-btn" class="bg-gray-200 hover:bg-gray-300 text-gray-800 font-medium py-2 px-4 rounded-lg transition-all-300 flex items-center justify-center">
            <i class="fa-solid fa-trash mr-2"></i>清空接收区
          </button>
        </div>
      </div>
      
      <div class="mt-4">
        <div class="flex items-center justify-between mb-2">
          <h3 class="font-medium text-gray-800">串口通信数据</h3>
          <div class="flex items-center space-x-2">
            <label class="inline-flex items-center">
              <input type="checkbox" id="hex-view" class="form-checkbox h-4 w-4 text-primary rounded border-gray-300 focus:ring-primary/50" checked>
              <span class="ml-1 text-xs text-gray-700">Hex显示</span>
            </label>
            <label class="inline-flex items-center">
              <input type="checkbox" id="auto-scroll" class="form-checkbox h-4 w-4 text-primary rounded border-gray-300 focus:ring-primary/50" checked>
              <span class="ml-1 text-xs text-gray-700">自动滚屏</span>
            </label>
          </div>
        </div>
        
        <div class="grid grid-cols-1 gap-4">
          <div>
            <label class="block text-xs text-gray-500 mb-1">发送数据</label>
            <div id="tx-data" class="font-mono text-gray-800 bg-gray-50 p-3 rounded-lg border border-gray-200 h-24 overflow-y-auto text-sm">
              <!-- 发送数据将显示在这里 -->
            </div>
          </div>
          
          <div>
            <label class="block text-xs text-gray-500 mb-1">接收数据</label>
            <div id="rx-data" class="font-mono text-gray-800 bg-gray-50 p-3 rounded-lg border border-gray-200 h-40 overflow-y-auto text-sm">
              <!-- 接收数据将显示在这里 -->
            </div>
          </div>
        </div>
      </div>
    </section>
  </main>

  <!-- 页脚 -->
  <footer class="bg-gray-800 text-white py-4 mt-6">
    <div class="container mx-auto px-4 text-center text-sm">
      <p>通信协议生成器与串口通信工具 &copy; 2025</p>
      <p class="mt-1 text-gray-400">使用 HTML, JavaScript 和 Tailwind CSS 构建</p>
    </div>
  </footer>

  <!-- 帮助模态框 -->
  <div id="help-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
    <div class="bg-white rounded-xl shadow-2xl max-w-2xl w-full max-h-[90vh] overflow-y-auto m-4">
      <div class="p-6 border-b border-gray-200">
        <div class="flex justify-between items-center">
          <h3 class="text-xl font-bold text-gray-800">使用帮助</h3>
          <button id="close-help" class="text-gray-500 hover:text-gray-700">
            <i class="fa-solid fa-times"></i>
          </button>
        </div>
      </div>
      <div class="p-6 space-y-4">
        <div>
          <h4 class="font-medium text-gray-800 mb-2">协议生成部分</h4>
          <p class="text-gray-600 text-sm">
            1. 选择要操作的通道（通道1或通道2）。<br>
            2. 选择要执行的功能（波形设置、频率设置或相位设置）。<br>
            3. 根据所选功能设置相应的参数值。<br>
            4. 频率输入为十进制格式（范围0-10000kHz），系统会自动转换为对应的8位十六进制表示。<br>
            5. 点击"计算校验并生成协议"按钮，系统将自动计算校验和并生成完整的协议数据包。
          </p>
        </div>
        <div>
          <h4 class="font-medium text-gray-800 mb-2">串口通信部分</h4>
          <p class="text-gray-600 text-sm">
            1. 点击"连接串口"按钮，选择可用的串口端口。<br>
            2. 设置波特率、数据位、校验位和停止位等参数。<br>
            3. 连接成功后，点击"发送数据包"按钮将生成的协议数据包通过串口发送。<br>
            4. 发送和接收的数据将分别显示在"发送数据"和"接收数据"区域。<br>
            5. 可以使用"清空发送区"和"清空接收区"按钮清除相应区域的内容。
          </p>
        </div>
        <div>
          <h4 class="font-medium text-gray-800 mb-2">注意事项</h4>
          <p class="text-gray-600 text-sm">
            1. 该工具使用浏览器的Web Serial API，需要在支持此API的现代浏览器中使用（如Chrome、Edge等）。<br>
            2. 串口通信功能需要用户授权，并且只能在安全的上下文（HTTPS）或本地环境中使用。<br>
            3. 校验算法为和校验，即将包头、命令、数据长度和数据进行累加，并取低8位作为校验结果。
          </p>
        </div>
      </div>
      <div class="p-4 bg-gray-50 rounded-b-xl">
        <button id="close-help-btn" class="bg-primary hover:bg-primary/90 text-white font-medium py-2 px-4 rounded-lg transition-all-300">
          我知道了
        </button>
      </div>
    </div>
  </div>

  <script>
    // 全局变量
    let serialPort = null;
    let outputStream = null;
    let inputStream = null;
    let reader = null;
    let isReceiving = false;
    
    // DOM元素
    const generateBtn = document.getElementById('generate-btn');
    const protocolResult = document.getElementById('protocol-result');
    const resultHeader = document.getElementById('result-header');
    const resultCommand = document.getElementById('result-command');
    const resultDataLength = document.getElementById('result-data-length');
    const resultData = document.getElementById('result-data');
    const resultChecksum = document.getElementById('result-checksum');
    const resultFullPacket = document.getElementById('result-full-packet');
    const serialPortSelect = document.getElementById('serial-port');
    const baudRateSelect = document.getElementById('baud-rate');
    const dataBitsSelect = document.getElementById('data-bits');
    const paritySelect = document.getElementById('parity');
    const stopBitsSelect = document.getElementById('stop-bits');
    const connectBtn = document.getElementById('connect-btn');
    const disconnectBtn = document.getElementById('disconnect-btn');
    const sendBtn = document.getElementById('send-btn');
    const clearTxBtn = document.getElementById('clear-tx-btn');
    const clearRxBtn = document.getElementById('clear-rx-btn');
    const txData = document.getElementById('tx-data');
    const rxData = document.getElementById('rx-data');
    const hexViewCheckbox = document.getElementById('hex-view');
    const autoScrollCheckbox = document.getElementById('auto-scroll');
    const connectionStatus = document.getElementById('connection-status');
    const connectionText = document.getElementById('connection-text');
    const portInfo = document.getElementById('port-info');
    const serialStatus = document.getElementById('serial-status');
    const serialActions = document.getElementById('serial-actions');
    const helpBtn = document.getElementById('help-btn');
    const helpModal = document.getElementById('help-modal');
    const closeHelp = document.getElementById('close-help');
    const closeHelpBtn = document.getElementById('close-help-btn');
    const themeToggle = document.getElementById('theme-toggle');
    // 命令选择
    const channelSelect = document.getElementById('channel-select');
    const functionSelect = document.getElementById('function-select');
    const parameterTitle = document.getElementById('parameter-title');
    // 波形设置
    const waveformSettings = document.getElementById('waveform-settings');
    const waveformValue = document.getElementById('waveform-value');
    // 频率设置
    const frequencySettings = document.getElementById('frequency-settings');
    const frequencyValue = document.getElementById('frequency-value');
    const frequencyHex = document.getElementById('frequency-hex');
    // 相位设置
    const phaseSettings = document.getElementById('phase-settings');
    const phaseValue = document.getElementById('phase-value');
    
    // 初始化页面
    document.addEventListener('DOMContentLoaded', () => {
      // 检查浏览器是否支持Web Serial API
      if (!('serial' in navigator)) {
        showError('您的浏览器不支持Web Serial API，请使用Chrome或Edge等现代浏览器。');
        connectBtn.disabled = true;
      }
      
      // 初始化频率输入转换
      frequencyValue.addEventListener('input', updateFrequencyHex);
      
      // 初始更新频率显示
      updateFrequencyHex();
      
      // 命令选择事件
      channelSelect.addEventListener('change', updateParameterUI);
      functionSelect.addEventListener('change', updateParameterUI);
      
      // 初始更新参数UI
      updateParameterUI();
      
      // 事件监听
      generateBtn.addEventListener('click', generateProtocol);
      connectBtn.addEventListener('click', connectSerial);
      disconnectBtn.addEventListener('click', disconnectSerial);
      sendBtn.addEventListener('click', sendPacket);
      clearTxBtn.addEventListener('click', () => { txData.textContent = ''; });
      clearRxBtn.addEventListener('click', () => { rxData.textContent = ''; });
      helpBtn.addEventListener('click', () => { helpModal.classList.remove('hidden'); });
      closeHelp.addEventListener('click', () => { helpModal.classList.add('hidden'); });
      closeHelpBtn.addEventListener('click', () => { helpModal.classList.add('hidden'); });
      
      // 主题切换
      themeToggle.addEventListener('click', toggleTheme);
      
      // 初始化示例数据
      generateProtocol();
    });
    
    // 更新频率的十六进制显示 - 调整为8位十六进制
    function updateFrequencyHex() {
      const frequency = parseInt(frequencyValue.value) || 0;
      // 转换为8位十六进制表示（两个字节）
      const highByte = (frequency >> 8) & 0xFF;
      const lowByte = frequency & 0xFF;
      frequencyHex.textContent = `0x${highByte.toString(16).padStart(2, '0').toUpperCase()} 0x${lowByte.toString(16).padStart(2, '0').toUpperCase()}`;
    }
    
    // 更新参数UI显示
    function updateParameterUI() {
      const channel = channelSelect.value;
      const func = functionSelect.value;
      
      // 更新标题
      let title = '';
      switch (func) {
        case 'waveform':
          title = `通道 ${channel} 波形设置`;
          break;
        case 'frequency':
          title = `通道 ${channel} 频率设置`;
          break;
        case 'phase':
          title = `通道 ${channel} 相位设置`;
          break;
      }
      parameterTitle.textContent = title;
      
      // 显示对应的设置区域
      waveformSettings.classList.add('hidden');
      frequencySettings.classList.add('hidden');
      phaseSettings.classList.add('hidden');
      
      switch (func) {
        case 'waveform':
          waveformSettings.classList.remove('hidden');
          break;
        case 'frequency':
          frequencySettings.classList.remove('hidden');
          break;
        case 'phase':
          phaseSettings.classList.remove('hidden');
          break;
      }
    }
    
    // 生成协议数据包
    function generateProtocol() {
      try {
        const channel = parseInt(channelSelect.value);
        const func = functionSelect.value;
        
        // 固定包头值
        const header = 0x55;
        
        // 根据通道和功能确定命令字节
        // 通道 1: 波形 (0x00), 频率 (0x02), 相位 (0x04)
        // 通道 2: 波形 (0x01), 频率 (0x03), 相位 (0x05)
        let command = 0x00;
        switch (channel) {
          case 1:
            switch (func) {
              case 'waveform':
                command = 0x00;
                break;
              case 'frequency':
                command = 0x02;
                break;
              case 'phase':
                command = 0x04;
                break;
            }
            break;
          case 2:
            switch (func) {
              case 'waveform':
                command = 0x01;
                break;
              case 'frequency':
                command = 0x03;
                break;
              case 'phase':
                command = 0x05;
                break;
            }
            break;
        }
        
        // 根据功能构建数据数组
        let dataArray = [];
        switch (func) {
          case 'waveform':
            const waveform = parseInt(waveformValue.value, 16);
            dataArray = [waveform];
            break;
          case 'frequency':
            const frequency = parseInt(frequencyValue.value) || 0;
            // 验证频率输入 - 范围0-10000
            if (isNaN(frequency) || frequency < 0 || frequency > 10000) {
              showError('频率格式不正确，请输入0 - 10000之间的整数');
              return;
            }
            // 转换为8位十六进制表示（两个字节）
            const frequencyHigh = (frequency >> 8) & 0xFF;
            const frequencyLow = frequency & 0xFF;
            dataArray = [frequencyHigh, frequencyLow];
            break;
          case 'phase':
            const phase = parseInt(phaseValue.value);
            // 验证相位输入
            if (isNaN(phase) || phase < 0 || phase > 4096) {
              showError('相位格式不正确，请输入0 - 4096之间的整数');
              return;
            }
            // 转换为两个字节
            dataArray = [(phase >> 8) & 0xff, phase & 0xff];
            break;
        }
        
        // 计算校验和
        let sum = header + command + dataArray.length;
        dataArray.forEach(byte => {
          sum += byte;
        });
        const checksum = sum & 0xff;
        
        // 构建完整数据包
        const fullPacket = [header, command, dataArray.length, ...dataArray, checksum];
        
        // 格式化显示结果
        resultHeader.textContent = formatHexByte(header);
        resultCommand.textContent = formatHexByte(command);
        resultDataLength.textContent = formatHexByte(dataArray.length);
        resultData.textContent = dataArray.map(formatHexByte).join(' ');
        resultChecksum.textContent = formatHexByte(checksum);
        resultFullPacket.textContent = fullPacket.map(formatHexByte).join(' ');
        
        // 显示结果区域
        protocolResult.classList.remove('hidden');
        
        // 添加动画效果
        protocolResult.classList.add('animate-pulse');
        setTimeout(() => {
          protocolResult.classList.remove('animate-pulse');
        }, 500);
        
        // 如果串口已连接，启用发送按钮
        if (serialPort && serialPort.opened) {
          sendBtn.disabled = false;
        }
      } catch (error) {
        showError(`生成协议失败: ${error.message}`);
      }
    }
    
    // 连接串口
    async function connectSerial() {
      try {
        // 请求用户选择串口
        serialPort = await navigator.serial.requestPort({
          filters: [] // 空过滤器表示显示所有可用串口
        });
        
        // 获取串口信息并显示
        const info = serialPort.getInfo();
        serialPortSelect.innerHTML = `<option value="${info.usbProductId}">${info.usbVendorId ? `USB 设备: ${info.usbVendorId}:${info.usbProductId}` : '串口设备'}</option>`;
        portInfo.textContent = `${info.usbVendorId ? `USB 设备: ${info.usbVendorId}:${info.usbProductId}` : '串口设备'} | ${baudRateSelect.value} ${dataBitsSelect.value}${paritySelect.value.charAt(0).toUpperCase()}${stopBitsSelect.value}`;
        
        // 打开串口
        await serialPort.open({
          baudRate: parseInt(baudRateSelect.value),
          dataBits: parseInt(dataBitsSelect.value),
          parity: paritySelect.value,
          stopBits: parseInt(stopBitsSelect.value),
          bufferSize: 255,
          flowControl: 'none'
        });
        
        // 更新UI状态
        updateConnectionStatus(true);
        
        // 开始接收数据
        startReceiving();
        
        showMessage('串口连接成功');
      } catch (error) {
        showError(`连接串口失败: ${error.message}`);
      }
    }
    
    // 断开串口连接
    async function disconnectSerial() {
      try {
        // 停止接收数据
        isReceiving = false;
        if (reader) {
          await reader.cancel();
          reader = null;
        }
        
        // 关闭输出流
        if (outputStream) {
          await outputStream.getWriter().close();
          outputStream = null;
        }
        
        // 关闭输入流
        if (inputStream) {
          await inputStream.cancel();
          inputStream = null;
        }
        
        // 关闭串口
        if (serialPort) {
          await serialPort.close();
          serialPort = null;
        }
        
        // 更新UI状态
        updateConnectionStatus(false);
        
        showMessage('串口已断开连接');
      } catch (error) {
        showError(`断开连接失败: ${error.message}`);
      }
    }
    
    // 开始接收串口数据
    async function startReceiving() {
      try {
        if (!serialPort || !serialPort.readable) return;
        
        isReceiving = true;
        inputStream = serialPort.readable;
        reader = inputStream.getReader();
        
        while (isReceiving) {
          const { value, done } = await reader.read();
          if (done) break;
          
          // 处理接收到的数据
          processReceivedData(value);
        }
      } catch (error) {
        if (isReceiving) {
          showError(`接收数据失败: ${error.message}`);
          disconnectSerial();
        }
      } finally {
        if (reader) {
          reader.releaseLock();
          reader = null;
        }
      }
    }
    
    // 处理接收到的数据
    function processReceivedData(data) {
      const timestamp = new Date().toLocaleTimeString();
      
      if (hexViewCheckbox.checked) {
        // 十六进制显示
        const hexString = Array.from(data)
          .map(byte => byte.toString(16).padStart(2, '0').toUpperCase())
          .join(' ');
        appendToRxData(`[${timestamp}] 接收: ${hexString}`);
      } else {
        // 字符串显示
        const decoder = new TextDecoder();
        const text = decoder.decode(data);
        appendToRxData(`[${timestamp}] 接收: ${text}`);
      }
    }
    
    // 发送数据包
    async function sendPacket() {
      try {
        if (!serialPort || !serialPort.writable) {
          showError('串口未连接');
          return;
        }
        
        // 获取当前生成的数据包
        const fullPacketStr = resultFullPacket.textContent;
        const bytes = fullPacketStr.trim()
          .split(' ')
          .map(hex => parseInt(hex, 16));
        
        // 创建输出流
        outputStream = serialPort.writable;
        const writer = outputStream.getWriter();
        
        // 发送数据
        const dataArray = new Uint8Array(bytes);
        await writer.write(dataArray);
        
        // 释放写锁
        writer.releaseLock();
        
        // 记录发送的数据
        const timestamp = new Date().toLocaleTimeString();
        appendToTxData(`[${timestamp}] 发送: ${fullPacketStr}`);
        
        // 添加发送动画效果
        sendBtn.classList.add('animate-pulse');
        setTimeout(() => {
          sendBtn.classList.remove('animate-pulse');
        }, 300);
      } catch (error) {
        showError(`发送数据失败: ${error.message}`);
      }
    }
    
    // 更新连接状态
    function updateConnectionStatus(connected) {
      if (connected) {
        connectionStatus.classList.remove('bg-gray-400', 'bg-danger');
        connectionStatus.classList.add('bg-success');
        connectionText.textContent = '已连接';
        connectionText.classList.remove('text-gray-500', 'text-danger');
        connectionText.classList.add('text-success');
        
        connectBtn.disabled = true;
        disconnectBtn.disabled = false;
        sendBtn.disabled = false;
        
        serialStatus.classList.remove('hidden');
        serialActions.classList.remove('hidden');
      } else {
        connectionStatus.classList.remove('bg-success', 'bg-danger');
        connectionStatus.classList.add('bg-gray-400');
        connectionText.textContent = '未连接';
        connectionText.classList.remove('text-success', 'text-danger');
        connectionText.classList.add('text-gray-500');
        
        connectBtn.disabled = false;
        disconnectBtn.disabled = true;
        sendBtn.disabled = true;
        
        serialStatus.classList.remove('hidden');
        serialActions.classList.add('hidden');
      }
    }
    
    // 辅助函数：格式化字节为十六进制字符串
    function formatHexByte(byte) {
      return `0x${byte.toString(16).padStart(2, '0').toUpperCase()}`;
    }
    
    // 辅助函数：添加文本到发送区域
    function appendToTxData(text) {
      txData.textContent += text + '\n';
      if (autoScrollCheckbox.checked) {
        txData.scrollTop = txData.scrollHeight;
      }
    }
    
    // 辅助函数：添加文本到接收区域
    function appendToRxData(text) {
      rxData.textContent += text + '\n';
      if (autoScrollCheckbox.checked) {
        rxData.scrollTop = rxData.scrollHeight;
      }
    }
    
    // 辅助函数：显示错误消息
    function showError(message) {
      // 创建错误提示元素
      const errorToast = document.createElement('div');
      errorToast.className = 'fixed top-4 right-4 bg-danger text-white px-4 py-2 rounded-lg shadow-lg z-50 transform transition-all duration-300 translate-y-0';
      errorToast.innerHTML = `<i class="fa-solid fa-exclamation-circle mr-2"></i>${message}`;
      
      // 添加到页面
      document.body.appendChild(errorToast);
      
      // 3秒后移除
      setTimeout(() => {
        errorToast.classList.add('translate-y-[-20px]', 'opacity-0');
        setTimeout(() => {
          document.body.removeChild(errorToast);
        }, 300);
      }, 3000);
    }
    
    // 辅助函数：显示普通消息
    function showMessage(message) {
      // 创建消息提示元素
      const messageToast = document.createElement('div');
      messageToast.className = 'fixed top-4 right-4 bg-success text-white px-4 py-2 rounded-lg shadow-lg z-50 transform transition-all duration-300 translate-y-0';
      messageToast.innerHTML = `<i class="fa-solid fa-check-circle mr-2"></i>${message}`;
      
      // 添加到页面
      document.body.appendChild(messageToast);
      
      // 3秒后移除
      setTimeout(() => {
        messageToast.classList.add('translate-y-[-20px]', 'opacity-0');
        setTimeout(() => {
          document.body.removeChild(messageToast);
        }, 300);
      }, 3000);
    }
    
    // 切换主题
    function toggleTheme() {
      const body = document.body;
      if (body.classList.contains('bg-gray-50')) {
        body.classList.remove('bg-gray-50');
        body.classList.add('bg-gray-900', 'text-white');
        themeToggle.innerHTML = '<i class="fa-solid fa-sun"></i>';
        
        // 更新卡片样式
        document.querySelectorAll('.bg-white').forEach(el => {
          el.classList.remove('bg-white');
          el.classList.add('bg-gray-800');
        });
        
        // 更新文本颜色
        document.querySelectorAll('.text-gray-800').forEach(el => {
          el.classList.remove('text-gray-800');
          el.classList.add('text-white');
        });
        
        // 更新边框颜色
        document.querySelectorAll('.border-gray-200').forEach(el => {
          el.classList.remove('border-gray-200');
          el.classList.add('border-gray-700');
        });
        
        // 更新背景色
        document.querySelectorAll('.bg-gray-50').forEach(el => {
          el.classList.remove('bg-gray-50');
          el.classList.add('bg-gray-700/50');
        });
      } else {
        body.classList.add('bg-gray-50');
        body.classList.remove('bg-gray-900', 'text-white');
        themeToggle.innerHTML = '<i class="fa-solid fa-moon"></i>';
        
        // 恢复卡片样式
        document.querySelectorAll('.bg-gray-800').forEach(el => {
          el.classList.add('bg-white');
          el.classList.remove('bg-gray-800');
        });
        
        // 恢复文本颜色
        document.querySelectorAll('.text-white').forEach(el => {
          if (el.id !== 'connection-text' && el.id !== 'connection-status') {
            el.classList.add('text-gray-800');
            el.classList.remove('text-white');
          }
        });
        
        // 恢复边框颜色
        document.querySelectorAll('.border-gray-700').forEach(el => {
          el.classList.add('border-gray-200');
          el.classList.remove('border-gray-700');
        });
        
        // 恢复背景色
        document.querySelectorAll('.bg-gray-700/50').forEach(el => {
          el.classList.add('bg-gray-50');
          el.classList.remove('bg-gray-700/50');
        });
      }
    }
  </script>
</body>
</html>
    